package com.niodata.dp.web.module.task;

import com.google.common.base.Strings;
import com.niodata.dp.log.LogUtil;
import com.niodata.dp.task.log.TaskLogManager;
import com.niodata.dp.util.StringUtil;
import com.niodata.dp.web.module.task.LogConsoleController.LogConsole;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

@Component("loggerHandler")
public class LoggerHandler extends TextWebSocketHandler {

  public static final String consoleId = "id";
  private static final Logger logger = Logger.getLogger(LoggerHandler.class);
  ExecutorService executorService = Executors.newFixedThreadPool(10);

  @Autowired
  LogConsoleManager logConsoleManager;

  @Autowired
  @Qualifier("taskLogManager")
  TaskLogManager taskLogManager;

  @Override
  public void afterConnectionEstablished(WebSocketSession session) {
    logger.info("add session:" + session.getId() + ",attr size:" + session.getAttributes().size());
    try {
      String id = session.getAttributes().get(consoleId).toString();
      logger.info("console id:" + id);
      LogConsole logConsole = logConsoleManager.get(id);
      if (null == logConsole) {
        logger.error("logConsole is null.");
      }
      Runnable processLog = new Runnable() {
        @Override
        public void run() {
          while (session.isOpen()) {
            try {
              String line = logConsole.viewerSession.readLine();
              if (StringUtil.isNotEmpty(line)) {
                session.sendMessage(new TextMessage(line));
              }
            } catch (Exception e) {
              LogUtil.logStackTrace(logger, e);
            }
          }
          logger.info("session is closed.");
        }
      };
      executorService.execute(processLog);
    } catch (Exception e) {
      LogUtil.logStackTrace(logger, e);
    }
  }

  @Override
  public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
    super.handleTransportError(session, exception);
    LogUtil.logStackTrace(logger, new Exception(exception));
  }

  @Override
  public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
    logger.info("remove session" + session.getId());
    super.afterConnectionClosed(session, status);
    String id = session.getAttributes().get(consoleId).toString();
    LogConsole console = logConsoleManager.get(id);
    if (console != null) {
      console.viewerSession.close();
      console.viewerSession.clear();
    }

    if (session.isOpen()) {
      session.close();
    }
  }

  @Override
  protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
    logger.info("Received:" + message.toString());
  }

  public static class LoggerHandshakeInterceptor extends HttpSessionHandshakeInterceptor {

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
          WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {

      String id = ((ServletServerHttpRequest) request).getServletRequest()
            .getParameter(consoleId);

      if (!Strings.isNullOrEmpty(id)) {
        attributes.put(consoleId, id);
      } else {
        return false;
      }
      return super.beforeHandshake(request, response, wsHandler, attributes);
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
          WebSocketHandler wsHandler, Exception ex) {
      super.afterHandshake(request, response, wsHandler, ex);
    }
  }
}
